package com.gcloud.mesh.distributedSchedule.evaluateFactor;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import com.gcloud.mesh.distributedSchedule.IApplication;
import com.gcloud.mesh.distributedSchedule.ICluster;
import com.gcloud.mesh.distributedSchedule.IEvaluateFactor;
import com.gcloud.mesh.distributedSchedule.application.Application;

import lombok.extern.slf4j.Slf4j;

/**
 * 评估电网负载安全性，防止超载。如何预测电网负载呢？目前来说，只能进行概略估计
 * TODO: 对应用的功耗和IDC的功耗情况进行基于时间的预测
 */
@Slf4j
public class PowerNetSecurityFactor extends EvaluateFactor implements IEvaluateFactor {

    public static String nameId = "powernet_security_factor";

    @Override
    public evalResult evaluate(Application[] scheduleAppList, ConcurrentHashMap<String, ICluster> targetClusters, String[] clusterIds) {
        evalResult er = new evalResult(nameId);
        HashMap<String, Set<Integer>> cltSort = this.sort(clusterIds);

        List<String> moveInApps = new ArrayList<>();
        for (String cltId: cltSort.keySet()) {
            moveInApps.clear();
            for (Integer index : cltSort.get(cltId)) {
                Application app = scheduleAppList[index.intValue()];
                if (! app.getClusterId().equals(app.getMigrateCluster())) {
                    // this is a new move in app.
                    moveInApps.add(app.getAppId());
                }
            }
            ICluster clt = targetClusters.get(cltId);
            HashMap<String, IApplication> appMap = clt.getAppMap();
            // minus 20% background power dissipation.
            double perAppPower = (clt.getInstantPowerKWH() - clt.getMaxInputPowerKwh() * 0.2) / appMap.size();
            // exceed the secure rate of maxInputPower

            double afterMigPower = clt.getInstantPowerKWH() + perAppPower * moveInApps.size();
            if (er.qualified == true && afterMigPower > clt.getMaxInputPowerKwh() * clt.getSecurePowerRate()) {
                log.warn(cltId + ": 超出功率安全范围:" + moveInApps.toString());
                er.qualified = false;
            }
            // 将迁移后剩下的功率空间作为得分
            double score = clt.getMaxInputPowerKwh() - afterMigPower;
            er.score += score < 0 ? 0 : score;
        }

        return er;
    }
}
